﻿// Decompiled with JetBrains decompiler
// Type: TaleWorlds.CampaignSystem.MapEvents.LootCollector
// Assembly: TaleWorlds.CampaignSystem, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: E85F8C15-4DF6-4E9C-A58A-29177E40D07A
// Assembly location: D:\steam\steamapps\common\Mount & Blade II Bannerlord\bin\Win64_Shipping_Client\TaleWorlds.CampaignSystem.dll

using Helpers;
using System;
using System.Collections.Generic;
using System.Linq;
using TaleWorlds.CampaignSystem.Actions;
using TaleWorlds.CampaignSystem.Party;
using TaleWorlds.CampaignSystem.Roster;
using TaleWorlds.Core;
using TaleWorlds.Library;

#nullable disable
namespace TaleWorlds.CampaignSystem.MapEvents
{
  internal class LootCollector
  {
    internal static void AutoGeneratedStaticCollectObjectsLootCollector(
      object o,
      List<object> collectedObjects)
    {
      ((LootCollector) o).AutoGeneratedInstanceCollectObjects(collectedObjects);
    }

    protected virtual void AutoGeneratedInstanceCollectObjects(List<object> collectedObjects)
    {
    }

    internal TroopRoster LootedMembers { get; private set; }

    internal TroopRoster LootedPrisoners { get; private set; }

    internal Dictionary<PartyBase, ItemRoster> LootedItems { get; private set; }

    public TroopRoster CasualtiesInBattle { get; private set; }

    internal LootCollector()
    {
      this.LootedMembers = TroopRoster.CreateDummyTroopRoster();
      this.LootedPrisoners = TroopRoster.CreateDummyTroopRoster();
      this.LootedItems = new Dictionary<PartyBase, ItemRoster>();
      this.CasualtiesInBattle = TroopRoster.CreateDummyTroopRoster();
    }

    internal void AddLootedItems(
      PartyBase lootedParty,
      EquipmentElement equipmentElement,
      int number)
    {
      ItemRoster itemRoster1;
      if (this.LootedItems.TryGetValue(lootedParty, out itemRoster1))
      {
        itemRoster1.AddToCounts(equipmentElement, number);
      }
      else
      {
        ItemRoster itemRoster2 = new ItemRoster();
        itemRoster2.AddToCounts(equipmentElement, number);
        this.LootedItems.Add(lootedParty, itemRoster2);
      }
    }

    public void MakeRemainingPrisonerHeroesEscape()
    {
      foreach (TroopRosterElement troopRosterElement in (IEnumerable<TroopRosterElement>) this.LootedMembers.RemoveIf((Predicate<TroopRosterElement>) (lordElement => lordElement.Character.IsHero && !lordElement.Character.HeroObject.IsHumanPlayerCharacter && !lordElement.Character.HeroObject.CanBecomePrisoner())))
        MakeHeroFugitiveAction.Apply(troopRosterElement.Character.HeroObject);
    }

    internal void MakeFreedHeroesEscape(TroopRoster freedTroops, bool wonByPlayer = false)
    {
      for (int index = freedTroops.Count - 1; index >= 0; --index)
      {
        CharacterObject characterAtIndex = freedTroops.GetCharacterAtIndex(index);
        if (characterAtIndex.IsHero && !wonByPlayer)
        {
          if (!characterAtIndex.IsPlayerCharacter)
            EndCaptivityAction.ApplyByReleasedAfterBattle(characterAtIndex.HeroObject);
          freedTroops.RemoveTroop(characterAtIndex);
        }
      }
    }

    internal void GiveShareOfLootToParty(
      TroopRoster memberRoster,
      TroopRoster prisonerRoster,
      ItemRoster itemRoster,
      PartyBase winnerParty,
      float lootAmount,
      MapEvent mapEvent)
    {
      bool flag1 = winnerParty == PartyBase.MainParty;
      bool flag2 = winnerParty.IsMobile && winnerParty.MobileParty.IsMilitia;
      bool flag3 = winnerParty.IsMobile && winnerParty.MobileParty.IsGarrison;
      bool flag4 = flag2 && winnerParty.MobileParty.CurrentSettlement != null && winnerParty.MobileParty.CurrentSettlement.IsVillage;
      bool flag5 = winnerParty.IsMobile && winnerParty.MobileParty.IsVillager;
      bool flag6 = winnerParty.IsMobile && winnerParty.MobileParty.IsCaravan;
      bool flag7 = winnerParty.IsMobile && winnerParty.MobileParty.IsBandit;
      List<TroopRosterElement> troopRosterElementList = new List<TroopRosterElement>((int) ((double) this.LootedMembers.TotalManCount * (double) MathF.Min(lootAmount * 1.3f, 1f)));
      foreach (TroopRosterElement troopRosterElement1 in (List<TroopRosterElement>) this.LootedMembers.GetTroopRoster())
      {
        int number = troopRosterElement1.Number;
        CharacterObject character = troopRosterElement1.Character;
        TroopRosterElement troopRosterElement2;
        if (character.IsPlayerCharacter)
        {
          troopRosterElement2 = new TroopRosterElement(character);
          troopRosterElement2.Number = 1;
          troopRosterElement2.WoundedNumber = 1;
          TroopRosterElement troopRosterElement3 = troopRosterElement2;
          troopRosterElementList.Add(troopRosterElement3);
        }
        else
        {
          for (int index = 0; index < number; ++index)
          {
            if ((double) MBRandom.RandomFloat < (double) lootAmount)
            {
              troopRosterElement2 = new TroopRosterElement(character);
              troopRosterElement2.Number = 1;
              troopRosterElement2.WoundedNumber = 1;
              TroopRosterElement troopRosterElement4 = troopRosterElement2;
              troopRosterElementList.Add(troopRosterElement4);
            }
          }
        }
      }
      foreach (TroopRosterElement troopRosterElement in troopRosterElementList)
        this.LootedMembers.AddToCounts(troopRosterElement.Character, -1);
      foreach (TroopRosterElement troopRosterElement in troopRosterElementList)
      {
        PartyBase capturerParty = winnerParty;
        if (flag2 | flag3)
        {
          capturerParty = winnerParty.MobileParty.HomeSettlement.Party;
          prisonerRoster = capturerParty.PrisonRoster;
        }
        if (troopRosterElement.Character.IsHero)
        {
          if (!flag1 && winnerParty.IsMobile)
          {
            TakePrisonerAction.Apply(capturerParty, troopRosterElement.Character.HeroObject);
            if (flag4 | flag5 | flag6 && !troopRosterElement.Character.IsPlayerCharacter)
              EndCaptivityAction.ApplyByReleasedAfterBattle(troopRosterElement.Character.HeroObject);
          }
          else if (!flag4)
            prisonerRoster.AddToCounts(troopRosterElement.Character, troopRosterElement.Number);
        }
        else if (!(flag4 | flag5 | flag6))
          prisonerRoster.AddToCounts(troopRosterElement.Character, troopRosterElement.Number);
      }
      float shareProbability = Campaign.Current.Models.BattleRewardModel.GetPartySavePrisonerAsMemberShareProbability(winnerParty, lootAmount);
      int num1 = winnerParty.IsMobile ? winnerParty.MobileParty.LimitedPartySize : winnerParty.PartySizeLimit;
      if ((double) shareProbability > 0.0)
      {
        for (int index1 = this.LootedPrisoners.Count - 1; index1 >= 0; --index1)
        {
          int elementNumber = this.LootedPrisoners.GetElementNumber(index1);
          CharacterObject characterAtIndex = this.LootedPrisoners.GetCharacterAtIndex(index1);
          int num2 = 0;
          for (int index2 = 0; index2 < elementNumber; ++index2)
          {
            int num3 = !characterAtIndex.IsHero ? 0 : (characterAtIndex.HeroObject.IsReleased ? 1 : 0);
            bool flag8 = flag7 && characterAtIndex.Occupation != Occupation.Bandit;
            bool flag9 = flag3 && characterAtIndex.Occupation == Occupation.Bandit;
            int num4 = flag8 ? 1 : 0;
            if ((num3 | num4 | (flag9 ? 1 : 0)) == 0 && (double) MBRandom.RandomFloat < (double) shareProbability)
            {
              if (flag1 || memberRoster.TotalManCount + 1 <= num1)
              {
                if (characterAtIndex.IsHero && !flag1)
                  EndCaptivityAction.ApplyByReleasedAfterBattle(characterAtIndex.HeroObject);
                else
                  memberRoster.AddToCounts(characterAtIndex, 1);
                ++num2;
              }
              else
                break;
            }
          }
          if (num2 > 0)
            this.LootedPrisoners.AddToCounts(characterAtIndex, -num2);
        }
      }
      MBList<TroopRosterElement> mbList = new MBList<TroopRosterElement>();
      for (int index3 = this.CasualtiesInBattle.Count - 1; index3 >= 0; --index3)
      {
        int elementNumber = this.CasualtiesInBattle.GetElementNumber(index3);
        CharacterObject characterAtIndex = this.CasualtiesInBattle.GetCharacterAtIndex(index3);
        int num5 = 0;
        TroopRosterElement troopRosterElement = new TroopRosterElement(characterAtIndex);
        for (int index4 = 0; index4 < elementNumber; ++index4)
        {
          if ((double) MBRandom.RandomFloat < (double) lootAmount)
          {
            mbList.Add(troopRosterElement);
            ++num5;
          }
        }
        if (num5 > 0)
          this.CasualtiesInBattle.AddToCounts(characterAtIndex, -num5);
      }
      if (flag3 | flag2)
        return;
      ItemRoster gainedLoot = new ItemRoster();
      CampaignEventDispatcher.Instance.CollectLoots(mapEvent, winnerParty, this.LootedItems, gainedLoot, mbList, lootAmount);
      for (int index = 0; index < gainedLoot.Count; ++index)
        itemRoster.Add(gainedLoot[index]);
      CampaignEventDispatcher.Instance.OnLootDistributedToParty(mapEvent, winnerParty, this.LootedItems);
      ExplainedNumber stat = new ExplainedNumber(1f);
      if (winnerParty.IsMobile)
      {
        CharacterObject partyLeaderForSkill = SkillHelper.GetEffectivePartyLeaderForSkill(winnerParty);
        if (partyLeaderForSkill != null)
          SkillHelper.AddSkillBonusForCharacter(DefaultSkills.Roguery, DefaultSkillEffects.RogueryLootBonus, partyLeaderForSkill, ref stat);
      }
      if (winnerParty == PartyBase.MainParty)
      {
        IEnumerable<ItemRosterElement> rosterElementList = this.LootCasualties((ICollection<TroopRosterElement>) mbList, stat.ResultNumber);
        itemRoster.Add(rosterElementList);
      }
      else
      {
        if (winnerParty.LeaderHero == null)
          return;
        int num6 = (int) ((double) MathF.Round((float) this.LootCasualtiesToGold((ICollection<TroopRosterElement>) mbList, stat.ResultNumber) * stat.ResultNumber) * (double) Campaign.Current.Models.BattleRewardModel.GetAITradePenalty());
        winnerParty.LeaderHero.Gold += num6;
      }
    }

    private IEnumerable<ItemRosterElement> LootCasualties(
      ICollection<TroopRosterElement> shareFromCasualties,
      float lootFactor)
    {
      ItemRoster itemRoster = new ItemRoster();
      List<EquipmentElement> source = new List<EquipmentElement>();
      foreach (TroopRosterElement shareFromCasualty in (IEnumerable<TroopRosterElement>) shareFromCasualties)
      {
        source.Clear();
        int num = MBRandom.RoundRandomized(lootFactor);
        for (int index = 0; index < num; ++index)
        {
          float targetValue = Campaign.Current.Models.BattleRewardModel.GetExpectedLootedItemValue(shareFromCasualty.Character) * MBRandom.RandomFloatRanged(0.75f, 1.25f);
          EquipmentElement lootedItem = Campaign.Current.Models.BattleRewardModel.GetLootedItemFromTroop(shareFromCasualty.Character, targetValue);
          if (lootedItem.Item != null && !lootedItem.Item.NotMerchandise && source.Count<EquipmentElement>((Func<EquipmentElement, bool>) (x => x.Item.Type == lootedItem.Item.Type)) == 0)
            itemRoster.AddToCounts(lootedItem, 1);
        }
      }
      return (IEnumerable<ItemRosterElement>) itemRoster;
    }

    private int LootCasualtiesToGold(
      ICollection<TroopRosterElement> shareFromCasualties,
      float lootFactor)
    {
      float gold = 0.0f;
      foreach (TroopRosterElement shareFromCasualty in (IEnumerable<TroopRosterElement>) shareFromCasualties)
        gold += Campaign.Current.Models.BattleRewardModel.GetExpectedLootedItemValue(shareFromCasualty.Character) * lootFactor;
      return (int) gold;
    }
  }
}
